/* ==============================================================================
*
*   Copyright (c) 2010, Pierre Favier
*   All rights reserved.
*
*   NTasking is free software: you can redistribute it and/or modify it
*   under the terms of the GNU General Public License as published by the
*   Free Software Foundation.
*
*   Redistribution and use in source and binary forms, with or without
*   modification, are permitted provided that the following conditions
*   are met:
*
*   -   Redistributions of source code must retain the above copyright notice,
*       this list of conditions and the following disclaimer.
*
*   -   Redistributions in binary form must reproduce the above
*       copyright notice, this list of conditions and the following
*       disclaimer in the documentation and/or other materials
*       provided with the distribution.
*
*   THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED
*   WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
*   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
*   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS
*   BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
*   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
*   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
*   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
*   ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR
*   TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
*   THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
*   SUCH DAMAGE.
*
* ============================================================================== */

using System;
using System.Threading;
using NTasking.ValidationTests.ACATS_3_0.Support;
using NUnit.Framework;
using Rhino.Mocks;

namespace NTasking.ValidationTests.ACATS_3_0.C9
{

    [TestFixture(Description = "")]
    public class C9740012 : ValidationTest
    {

        private static string NewPath;
        private static int DummyDeficiency = 520;
        private static bool PathAvailable = false;

        private static bool TerminateNegotiationExecuted = false;
        private static bool TriggerCompleted = false;
        private static bool NegotiationCompleted = false;


        private static LocalDeficit localDeficit = null;


        internal class LocalDeficit : Protected
        {
            private bool GoodVoltage = false;

            [ReadWriteOperation]
            internal Action SetGoodVoltage { get; private set; }

            [ReadWriteOperation]
            internal Action BadVoltage { get; private set; }

            [Entry]
            internal Action TerminateNegotiation { get; private set; }


            internal LocalDeficit()
            {
                ReadWriteOperation(SetGoodVoltage, () =>
                {
                    GoodVoltage = true;
                });


                ReadWriteOperation(BadVoltage, () =>
                {
                    GoodVoltage = false;
                });


                Entry(TerminateNegotiation,
                    When: () => GoodVoltage,
                Is: () =>
                {
                    // complete the triggering call thus terminating grid_path
                    // negotiation.
                    ; //::: stub - signal main board
                    TerminateNegotiationExecuted = true;   // show path traversal
                });
            }
        }

        
        // Routine to find the most cost effective grid path for this 
        // particular deficiency at this particular time
        //
        internal static string PathNegotiation(int requirement)
        {
            string DummyPath = "NYC.425_NY.227_NH.132";
            int Match = requirement;

            for (int i = 1; i <= 5; i++)
            {
                Ada.Delay(Impdef.MinimumTaskSwitch);
                // Part of the way through the negotiation simulate some external 
                // event returning the voltage to acceptable level 
                if (i == 3)
                    localDeficit.SetGoodVoltage(); // clear the barrier
            }

            NegotiationCompleted = true;
            return DummyPath;
        }

        
        [Test(Description =
            "Check that the abortable part of an asynchronous select statement is " +
            "aborted if it does not complete before the triggering statement " +
            "completes, where the triggering statement is a call on a protected " +
            "entry which is queued. ")]
        public void Test()
        {
            IValidationTestResult result = Mocks.DynamicMock<IValidationTestResult>();
            
            Ada.Declare(() =>
            {
                localDeficit = new LocalDeficit();

                // Setup test expectations

                Expect.Call(result.TestFailed).Repeat.Never();

                Mocks.ReplayAll();
            },
            Begin: () =>
            {
                // Start test execution

                localDeficit.BadVoltage();  // Set barrier condition

                // For the given voltage deficiency start negotiating the best grid
                // path.  If voltage returns to acceptable level cancel the negotiation
                
                Ada.Select(s =>
                    // Prepare to terminate the Path_Negotiation if voltage improves.
                    s.Call(localDeficit.TerminateNegotiation)().
                    Then(() =>
                    {
                        TriggerCompleted = true;
                    }).
                ThenAbort(() =>
                {
                    NewPath = PathNegotiation(DummyDeficiency);
                    PathAvailable = true;
                }));

                if (!TerminateNegotiationExecuted || !TriggerCompleted)
                    // Unexpected test path taken
                    result.TestFailed();

                if (PathAvailable || NegotiationCompleted)
                    // Abortable part was not aborted
                    result.TestFailed();
            });

        }

    }

}
